﻿using System;
using System.IO;
using Moq;
using NUnit.Framework;

namespace PhotoFramePublishingPlugin.Tests
{
    [TestFixture]
    public class ConfigurationSettingsPresenterTests
    {
        private const string InitialDestinationRoot = @"D:\Temp";
        private static readonly ImageSize InitialImageSize = new ImageSize("Small", 800, 600);
        private const bool InitialShouldAddBorders = false;
        private const bool InitialShouldShortenFileNames = false;

        private const string ExpectedDestinationRoot = @"C:\Temp";
        private static readonly ImageSize ExpectedImageSize = new ImageSize("Large", 1280, 1024);
        private const bool ExpectedShouldAddBorders = true;
        private const bool ExpectedShouldShortenFileNames = true;

        [Test]
        public void Constructor_LoadsFromModel()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              InitialShouldShortenFileNames);

            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            Assert.AreEqual(InitialDestinationRoot, presenter.DestinationRoot);
            Assert.AreEqual(InitialImageSize, presenter.ImageSize);
            Assert.AreEqual(InitialShouldAddBorders, presenter.ShouldAddBorders);
            Assert.AreEqual(InitialShouldShortenFileNames, presenter.ShouldShortenFileNames);
        }

        [Test]
        public void OnClickOkButton_SavesToModel()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));
            view.Setup(v => v.ClearDestinationError());

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              InitialShouldShortenFileNames);
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);

            presenter.DestinationRoot = ExpectedDestinationRoot;
            presenter.ImageSize = ExpectedImageSize;
            presenter.ShouldAddBorders = ExpectedShouldAddBorders;
            presenter.ShouldShortenFileNames = ExpectedShouldShortenFileNames;

            presenter.OnClickOkButton(this, EventArgs.Empty);

            Assert.AreEqual(ExpectedDestinationRoot, model.DestinationRoot);
            Assert.AreEqual(ExpectedImageSize, model.ImageSize);
            Assert.AreEqual(ExpectedShouldAddBorders, model.ShouldAddBorders);
            Assert.AreEqual(ExpectedShouldShortenFileNames, model.ShouldShortenFileNames);
        }

        [Test]
        public void EmptyDestinationRoot_DisablesOkButton_SetsDestinationError()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            string destinationError = null;
            //< TODO: Consider having this as a property. It makes testing a little easier.
            view.Setup(v => v.ClearDestinationError())
                .Callback(() => destinationError = "");
            view.Setup(v => v.SetDestinationError(It.IsAny<string>()))
                .Callback((string x) => destinationError = x);

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              InitialShouldShortenFileNames);
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);

            presenter.DestinationRoot = String.Empty;

            Assert.IsNotEmpty(destinationError);
            Assert.IsFalse(view.Object.OkButtonEnabled);
        }

        [Test]
        public void ValidDestinationRoot_EnablesOkButton_ClearsDestinationError()
        {
            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            string destinationError = null;
            //< TODO: Consider having this as a property. It makes testing a little easier.
            view.Setup(v => v.ClearDestinationError())
                .Callback(() => destinationError = "");
            view.Setup(v => v.SetDestinationError(It.IsAny<string>()))
                .Callback((string x) => destinationError = x);

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              InitialShouldShortenFileNames);
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);

            presenter.DestinationRoot = Directory.GetCurrentDirectory();

            Assert.IsEmpty(destinationError);
            Assert.IsTrue(view.Object.OkButtonEnabled);
        }

        [Test]
        public void WithDontAddBorders_CheckShouldAddBorders_RaisesPropertyChanged_ChangesImage()
        {
            BorderPreviewMode borderPreviewMode = BorderPreviewMode.Cropped;

            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.Setup(v => v.ClearDestinationError());
            view.SetupProperty(v => v.OkButtonEnabled);

            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()))
                .Callback((BorderPreviewMode m) => borderPreviewMode = m);

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              borderPreviewMode == BorderPreviewMode.WithBorders,
                                                                              InitialShouldShortenFileNames);

            bool propertyChangedWasRaised = false;
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.PropertyChanged += (sender, e) => { Assert.AreEqual("ShouldAddBorders", e.PropertyName); propertyChangedWasRaised = true; };

            presenter.ShouldAddBorders = true;
            Assert.AreEqual(BorderPreviewMode.WithBorders, borderPreviewMode);
            Assert.That(propertyChangedWasRaised, "PropertyChanged event was not raised");
        }

        [Test]
        public void WithAddBorders_UncheckShouldAddBorders_RaisesPropertyChanged_ChangesImage()
        {
            const bool shouldAddBorders = true;
            BorderPreviewMode borderPreviewMode = BorderPreviewMode.WithBorders;

            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.Setup(v => v.ClearDestinationError());
            view.SetupProperty(v => v.OkButtonEnabled);

            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()))
                .Callback((BorderPreviewMode m) => borderPreviewMode = m);

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              shouldAddBorders,
                                                                              InitialShouldShortenFileNames);

            bool propertyChangedWasRaised = false;
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.PropertyChanged += (sender, e) => { Assert.AreEqual("ShouldAddBorders", e.PropertyName); propertyChangedWasRaised = true; };

            presenter.ShouldAddBorders = false;
            Assert.AreEqual(BorderPreviewMode.Cropped, borderPreviewMode);
            Assert.That(propertyChangedWasRaised, "PropertyChanged event was not raised");
        }

        [Test]
        public void WithoutShortenFileNames_CheckShortenFileNames_RaisesPropertyChanged()
        {
            const bool shouldShortenFileNames = false;

            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.Setup(v => v.ClearDestinationError());
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              shouldShortenFileNames);

            bool propertyChangedWasRaised = false;
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.PropertyChanged += (sender, e) => { Assert.AreEqual("ShouldShortenFileNames", e.PropertyName); propertyChangedWasRaised = true; };

            presenter.ShouldShortenFileNames = true;
            Assert.That(propertyChangedWasRaised, "PropertyChanged event was not raised");
        }

        [Test]
        public void WithShortenFileNames_UncheckShortenFileNames_RaisesPropertyChanged()
        {
            const bool shouldShortenFileNames = true;

            Mock<IConfigurationSettingsView> view = new Mock<IConfigurationSettingsView>(MockBehavior.Strict);
            view.Setup(v => v.ClearDestinationError());
            view.SetupProperty(v => v.OkButtonEnabled);
            view.Setup(v => v.SetBorderPreview(It.IsAny<BorderPreviewMode>()));

            ConfigurationSettingsModel model = new ConfigurationSettingsModel(InitialImageSize.Width,
                                                                              InitialImageSize.Height,
                                                                              InitialDestinationRoot,
                                                                              InitialShouldAddBorders,
                                                                              shouldShortenFileNames);

            bool propertyChangedWasRaised = false;
            ConfigurationSettingsPresenter presenter = new ConfigurationSettingsPresenter(view.Object, model);
            presenter.PropertyChanged += (sender, e) => { Assert.AreEqual("ShouldShortenFileNames", e.PropertyName); propertyChangedWasRaised = true; };

            presenter.ShouldShortenFileNames = false;
            Assert.That(propertyChangedWasRaised, "PropertyChanged event was not raised");
        }
    }
}